package com.ymatou.iapi.trading.operate2.parameter.utill;

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.bson.types.ObjectId;
import org.joda.time.DateTime;
import org.joda.time.Days;
import org.joda.time.Hours;

/**
 * Created by zhangyifan on 2018/1/1.
 */
public class Utils {
	/**
	 * 默认格式
	 */
	public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";

	private static volatile String localIp;

	public static String uuid() {
		return new ObjectId().toHexString();
	}

	/**
	 * 处理null问题
	 *
	 * @return
	 */
	public static BigDecimal zeroIfNull(BigDecimal number) {
		BigDecimal zero = BigDecimal.ZERO;
		if (number == null)
			number = zero;

		return number;
	}
	/**
	 * 处理null问题
	 *
	 * @return
	 */
	public static Double zeroIfNull(Double number) {
		Double zero = 0D;
		if (number == null)
			number = zero;

		return number;
	}

	/**
	 * 处理null问题
	 *
	 * @return
	 */
	public static Integer zeroIfNull(Integer number) {
		Integer zero = 0;
		//return optional(number, zero);

		if (number == null)
			number = zero;

		return number;
	}
	/**
	 * 处理null问题
	 *
	 * @return
	 */
	public static Float zeroIfNull(Float number) {
		Float zero = 0F;
		if (number == null)
			number = zero;

		return number;
	}

	/**
	 * 处理null问题
	 *
	 * @return
	 */
	public static Long zeroIfNull(Long number) {
		Long zero = 0L;
		if (number == null)
			number = zero;

		return number;
	}

	/**
	 * 处理null问题
	 *
	 * @param b
	 * @return
	 */
	public static boolean falseIfNull(Boolean b) {
		boolean number = true;
		if (b == null)
			number = false;

		return number;
	}
	/**
	 * 根据权重平摊一个数额，且每个分摊结果项定义了最大允许值
	 *
	 * @param total
	 * @param weights
	 * @return
	 */
	public static BigDecimal[] apportionByWeightsAndMaxLimit(BigDecimal total,
			BigDecimal[] weights, BigDecimal[] maxs) {

		assert total.compareTo(BigDecimal.ZERO) >= 0 && weights != null
				&& weights.length > 0 && maxs != null
				&& maxs.length == weights.length;

		//首先完全按照权重分
		BigDecimal[] resultsByWeights = apportionByWeights(total, weights);

		//若需要二次分配时的权重和最大值配置
		List<BigDecimal> reapportionWights = new ArrayList<BigDecimal>();
		List<BigDecimal> reapportionMaxs = new ArrayList<BigDecimal>();
		BigDecimal totalReapportionWeights = BigDecimal.ZERO;

		//分配值已确定为最大值的项的Index
		Set<Integer> fixedIndexes = new HashSet<Integer>();

		BigDecimal fixedTotal = BigDecimal.ZERO;
		for (int i = 0; i < resultsByWeights.length; i++) {
			if (resultsByWeights[i].compareTo(maxs[i]) > 0) {
				resultsByWeights[i] = maxs[i];
				fixedTotal = fixedTotal.add(maxs[i]);
				fixedIndexes.add(i);
			} else {
				reapportionWights.add(weights[i]);
				reapportionMaxs.add(maxs[i]);
				totalReapportionWeights = totalReapportionWeights
						.add(weights[i]);
			}
		}
		if (fixedIndexes.size() > 0) {
			if (reapportionMaxs.size() > 0
					&& totalReapportionWeights.compareTo(BigDecimal.ZERO) > 0) {
				BigDecimal[] reResult = apportionByWeightsAndMaxLimit(
						total.subtract(fixedTotal),
						reapportionWights.toArray(new BigDecimal[0]),
						reapportionMaxs.toArray(new BigDecimal[0]));
				int j = 0;
				for (int i = 0; i < resultsByWeights.length; i++) {
					if (!fixedIndexes.contains(i)) {
						resultsByWeights[i] = reResult[j++];
					}
				}
			} else {
				throw new IllegalArgumentException("待分摊金额过大，无法按分摊比例及最大值限制分摊");
			}
		}

		return resultsByWeights;
	}

	public static int daysBetween(Date beginDate, Date endDate) {
		return Days.daysBetween(new DateTime(toDay(beginDate)),
				new DateTime(toDay(endDate))).getDays();
	}

	public static Date toDay(Date date) {
		Date result = DateUtils.setHours(date, 0);
		result = DateUtils.setMinutes(result, 0);
		result = DateUtils.setSeconds(result, 0);
		result = DateUtils.setMilliseconds(result, 0);
		return result;
	}

	/**
	 * 根据权重平摊一个数额
	 *
	 * @param total
	 * @param weights
	 * @return
	 */
	public static BigDecimal[] apportionByWeights(BigDecimal total,
			BigDecimal[] weights) {

		assert total.compareTo(BigDecimal.ZERO) >= 0 && weights != null
				&& weights.length > 0;

		if (total.compareTo(BigDecimal.ZERO) == 0) {
			BigDecimal[] result = new BigDecimal[weights.length];
			Arrays.fill(result, BigDecimal.ZERO);
			return result;
		}

		BigDecimal totalWeight = BigDecimal.ZERO;

		for (BigDecimal weight : weights) {
			totalWeight = totalWeight.add(weight);
		}

		if (totalWeight.compareTo(BigDecimal.ZERO) == 0) {
			throw new IllegalArgumentException("分摊权重未设置");
		}

		BigDecimal[] result = new BigDecimal[weights.length];

		BigDecimal sum = BigDecimal.ZERO;

		int lastNotZeroIndex = -1;
		for (int i = 0; i < weights.length - 1; i++) {

			// MathContext.DECIMAL32 参数用于防止无限循环小数导致的异常
			result[i] = weights[i].divide(totalWeight, MathContext.DECIMAL32)
					.multiply(total)
					// 小数点后2位的直接舍去
					.setScale(2, RoundingMode.DOWN);
			sum = sum.add(result[i]);

			if (weights[i].compareTo(BigDecimal.ZERO) > 0) {
				lastNotZeroIndex = i;
			}

		}

		if (weights[weights.length - 1].compareTo(BigDecimal.ZERO) == 0) {
			result[lastNotZeroIndex] = result[lastNotZeroIndex].add(total
					.subtract(sum));
			result[weights.length - 1] = BigDecimal.ZERO;
		} else {
			result[weights.length - 1] = total.subtract(sum);
		}

		return result;

	}

	public static BigDecimal devideThenMultiply(BigDecimal dividend,
			BigDecimal divisor, BigDecimal multiplier) {
		return dividend.divide(divisor, MathContext.DECIMAL32)
				.multiply(multiplier).setScale(2, RoundingMode.DOWN);
	}

	public static String trimAndLeft(String src, int n) {
		return StringUtils.left(StringUtils.trim(src), n);
	}

	public static List<String> splitAndTrim(String src, String separator) {
		if (src == null) {
			return null;
		}
		String[] splits = src.split(separator);
		List<String> result = new ArrayList<String>();
		for (String split : splits) {
			String trim = split.trim();
			if (trim.length() > 0) {
				result.add(trim);
			}
		}
		return result;
	}

	/**
	 * 计算目标时间和当前时间的差的小时值
	 *
	 * @param dt
	 * @return
	 */
	public static int calcTimeSpanHour(Date dt) {
		return Hours.hoursBetween(new DateTime(dt), DateTime.now()).getHours();
	}
}
